/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package overfeatfeatureextraction;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 *
 * @author mwh
 */
public class OverFeatFeatureExtraction {

    public static String overfeatLocation = "/home/mwh/tools/ml/overfeat/src/overfeat_batch";
    public static boolean printOverfeatOutput = true;
    static Logger logger = Logger.getLogger(OverFeatFeatureExtraction.class.getName());

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {


        Map<String, ImageResult> results = extractDir("/home/mwh/tools/ml/overfeat/samples-small");
        System.err.println(results);


    }

    public static Map<String, ImageResult> extractDir(String imagePath) throws IOException {

        Map<String, ImageResult> results = new HashMap<>();

        String outPath = imagePath + "-features";

        ProcessBuilder pb = new ProcessBuilder(overfeatLocation, "-i", imagePath, "-o", outPath);
        System.err.println(pb.command());
        System.err.println("Starting overfeat...");
        Process p = pb.start();
        BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        BufferedReader outputReader = new BufferedReader(new InputStreamReader(p.getInputStream()));

        String line;
        logger.log(Level.DEBUG, "----- STDERR -----");
        while ((line = errorReader.readLine()) != null) {
            logger.log(Level.DEBUG, line);
            System.err.println(line);
        }
        logger.log(Level.DEBUG, "----- STDOUT -----");
        while ((line = outputReader.readLine()) != null) {
            logger.log(Level.DEBUG, line);
            System.err.println(line);
        }
        errorReader.close();
        outputReader.close();
        logger.log(Level.DEBUG, "------------------");

        System.err.println("Overfeat finished...");

        File imagePathFile = new File(imagePath);
        File[] imageFiles = imagePathFile.listFiles(new ImageFileFilter());
        for (File imageFile : imageFiles) {
            String[] fnParts = imageFile.getName().split("\\.");
            System.err.println("filename: " + imageFile.getName());
            String imgName = fnParts[0];
            System.err.println("imagename: " + imgName);

            String featuresFileFN = outPath + "/" + imageFile.getName() + ".features";
            ImageResult imageResult = processFeatureFile(new File(featuresFileFN));
            results.put(imgName, imageResult);
        }


        return results;

    }

    public static ImageResult processFeatureFile(File file) throws IOException {

        BufferedReader reader = new BufferedReader(new FileReader(file));
        // Read headerline
        String line = reader.readLine();
        // Get output-size
        String[] dimsStr = line.split(" ");
        int size = Integer.parseInt(dimsStr[0]);

        List<float[]> featuresList = new ArrayList<>();
        // read features
        line = reader.readLine();
        String[] features = line.split(" ");
        float[] currentFeatures = new float[size];
        int currentIndex = 0;
        for (int i = 0; i < features.length; i++) {
            float val = Float.parseFloat(features[i]);
            currentFeatures[currentIndex] = val;

            currentIndex++;
            if (currentIndex == size) {
                featuresList.add(currentFeatures);
                currentFeatures = new float[size];
                currentIndex = 0;
            }

        }
        float[] maxFeatures = elementMax(featuresList);
//        System.err.println(maxFeatures.length);
//        System.err.println("");
//        System.err.println(Arrays.toString(maxFeatures));

        List<Float> maxFeaturesList = new ArrayList(maxFeatures.length);
        for (float f : maxFeatures) {
            maxFeaturesList.add(f);
        }
        
        AvroImageFeatures avroImageFeatures = AvroImageFeatures.newBuilder().
                setDescription("stdfe").
                setContent(maxFeaturesList).
                build();
        
        
        reader.close();
        ImageResult imageResult = new ImageResult();
        imageResult.addLayerFeatures(avroImageFeatures);


        return imageResult;
    }

    public static float[] elementMax(List<float[]> arrays) {

        int size = arrays.get(0).length;
        float[] maxArray = new float[size];
        Arrays.fill(maxArray, Float.NEGATIVE_INFINITY);

        for (float[] array : arrays) {
            for (int i = 0; i < size; i++) {
                maxArray[i] = Math.max(maxArray[i], array[i]);
            }
        }

        return maxArray;
    }
}
